package com.zxj.geekstudy.conc;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Supplier;

/**
 * 本周作业：（必做）思考有多少种方式，在main函数启动一个新线程或线程池，
 * 异步运行一个方法，拿到这个方法的返回值后，退出主线程？
 * 写出你的方法，越多越好，提交到github。
 *
 * 一个简单的代码参考：
 */
public class Homework03 {

    private static int result = 0;

    public static int get1() throws Exception {
        ExecutorService executor = Executors.newCachedThreadPool();
        Future<Integer> result = executor.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                return sum();
            }
        });
        executor.shutdown();
        return result.get();
    }

    public static int get2() throws Exception {
        FutureTask<Integer> result = new FutureTask<>(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                return sum();
            }
        });
        new Thread(result).start();
        return result.get();
    }

    public static int get3() throws Exception {
        Integer result = CompletableFuture.supplyAsync(new Supplier<Integer>() {

            @Override
            public Integer get() {
                return sum();
            }
        }).join();
        return result;
    }

    public static int get4() throws Exception {
        Object lock = new Object();
        Thread mainThread = Thread.currentThread();
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lock) {
                    result = sum();
                    lock.notify();
//                    mainThread.interrupt();
                }
            }
        });
        thread.start();
        synchronized (lock) {
            try {
                lock.wait();
            } catch (Exception e) {
            }
        }
        return result;
    }

    public static int get12() throws Exception {
        Thread mainThread = Thread.currentThread();
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                result = sum();
                mainThread.interrupt();
            }
        });
        thread.start();
        try {
            Thread.sleep(100000000000L);// 模拟永久休眠
        } catch (Exception e) {
        }
        return result;
    }

    public static int get9() throws Exception {
        Lock lock = new ReentrantLock();
        Condition condition = lock.newCondition();
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                lock.lock();
                try {
                    result = sum();
                    condition.signal();
                } finally {
                    lock.unlock();
                }
            }
        });
        thread.start();
        lock.lock();
        try {
            condition.await();
        } finally {
            lock.unlock();
        }
        return result;
    }

    public static int get10() throws Exception {
        Thread mainThread = Thread.currentThread();
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                result = sum();
//                LockSupport.unpark(mainThread);
                mainThread.interrupt();
            }
        });
        thread.start();
        LockSupport.park();
        return result;
    }

    public static int get5() throws Exception {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                result = sum();
            }
        });
        thread.start();
        thread.join();
        return result;
    }

    public static int get6() throws Exception {
        CountDownLatch countDownLatch = new CountDownLatch(1);
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                result = sum();
                countDownLatch.countDown();
            }
        });
        thread.start();
        countDownLatch.await();
        return result;
    }

    public static int get7() throws Exception {
        CyclicBarrier barrier  = new CyclicBarrier(2);
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                result = sum();
                try {
                    barrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }
        });
        thread.start();
        barrier.await();
        return result;
    }

    public static int get8() throws Exception {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                result = sum();
            }
        });
        thread.start();
        while (result == 0) {
//            Thread.sleep(100);
            Thread.yield();
        }
        return result;
    }

    public static int get11() throws Exception {
        AtomicBoolean atomicBoolean = new AtomicBoolean(false);
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                result = sum();
                atomicBoolean.compareAndSet(false, true);
            }
        });
        thread.start();
        while (!atomicBoolean.compareAndSet(true, false)) {
//            Thread.sleep(100);
            Thread.yield();
        }
        return result;
    }

    public static int get13() throws Exception {
        int count = Thread.activeCount();
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                result = sum();
            }
        });
        thread.start();
        while(Thread.activeCount() > count) {
//            Thread.sleep(100);
            Thread.yield();
        }
        return result;
    }

    public static void main(String[] args) throws Exception {
        
        long start=System.currentTimeMillis();

        // 在这里创建一个线程或线程池，
        // 异步执行 下面方法

        //这是得到的返回值
        int result = 0;
//        result = get1();
//        result = get2();
//        result = get3();
//        result = get4();
//        result = get5();
//        result = get6();
//        result = get7();
//        result = get8();
//        result = get9();
//        result = get10();
//        result = get11();
//        result = get12();
        result = get13();

        // 确保  拿到result 并输出
        System.out.println("异步计算结果为："+result);
         
        System.out.println("使用时间："+ (System.currentTimeMillis()-start) + " ms");
        
        // 然后退出main线程
    }
    
    private static int sum() {
        return fibo(36);
    }
    
    private static int fibo(int a) {
        if ( a < 2) 
            return 1;
        return fibo(a-1) + fibo(a-2);
    }
}
